package com.study.principle;

import org.springframework.beans.factory.annotation.Autowired;

/**
 * 6大设计原则：依赖倒置原则
 *
 * 两方面：
 *    * 抽象不应该依赖于细节，细节应当依赖于抽象（即针对接口而非实现编程）；
 *    * 在程序代码中传递参数时或在关联关系中，尽量引用层次高的抽象层类；
 *
 * 所谓高层次的抽象层类即使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明，以及数据类型的转换等，需要注意：
 *
 *    * 每个类尽量都有接口或抽象类，或者抽象类和接口两者都具备；
 *    * 变量的表名类型尽量是接口或者抽象类；
 *    * 尽量不要覆写基类的方法；
 *
 * 结合里氏替换原则使用。
 *
 * @Author 网易云课堂微专业-java高级开发工程师【allen老师】
 * @Version 1.0
 */
public class DependenceInversionPrinciple {
    public static void main(String[] args) {
//        Driver allen = new Driver();
//        Benz benz = new Benz();
//        // Allen 开奔驰车
//        allen.drive(benz);

        // 在新增加低层模块时，只修改了业务场景类，也就是高层模块，
        // 对其他低层模块如Driver类不需要做任何修改，业务就可以运行，把“变更”引起的风险扩散降低到最小。
        System.out.println("*************************");
        IDriver allen2 = new Driver2();
        ICar benz2 = new Benz2();
        // allen 开奔驰
        allen2.drive(benz2);
        // allen 还想开宝马
        ICar bmw = new BMW2();
        allen2.drive(bmw);
    }
}

// 汽车驾驶的一个例子

// 司机
class Driver {
    //司机的主要职责就是驾驶汽车
    public void drive(Benz benz) {
        benz.run();
    }
}

// 奔驰车
class Benz {
    //汽车肯定会跑
    public void run(){
        System.out.println("奔驰汽车开始运行...");
    }
}

/*
 1、 Allen老司机不仅要开奔驰车，还要开宝马车，又该怎么实现呢？
 */
// 宝马车
class BMW {
    public void run(){
        System.out.println("宝马汽车开始运行...");
    }
}

/*
 2、 宝马车也产生了，但是我们却没有办法让Allen开动起来，为什么？Allen没有开动宝马车的方法！
 */
interface IDriver {
    // 是老司机就应该会驾驶汽车
    public void drive(ICar car);
}

class Driver2 implements IDriver {
    // 司机的主要职责就是驾驶汽车
    @Override
    public void drive(ICar car) {
        car.run();
    }
}

interface ICar {
    //是汽车就应该能跑
    public void run();
}

interface ICar2 {
    public void runa();
    public void runb();
    public void runc();
}
interface ICar3 {
    public void xxoo();
}

class Benz2 implements ICar {
    // 汽车肯定会跑
    @Override
    public void run() {
        System.out.println("奔驰汽车开始运行...");
    }
}

class BMW2 implements ICar, ICar3 {
    // 宝马车当然也可以开动了
    @Override
    public void run() {
        System.out.println("宝马汽车开始运行...");
    }

    @Override
    public void xxoo() {
        System.out.println("宝马汽车xxoo...");
    }
}

/*
依赖的三种写法：1、构造函数传递依赖对象
 */
interface IDriver1 {
    //是司机就应该会驾驶汽车
    public void drive();
}

class Driver1 implements IDriver1 {
    private ICar car;

    //构造函数注入
    public Driver1(ICar car) {
        this.car = car;
    }

    //司机的主要职责就是驾驶汽车
    @Override
    public void drive() {
        this.car.run();
    }
}

/*
依赖的三种写法：2、Setter方法传递依赖对象
 */
interface IDriver2 {
    //车辆型号
    public void setCar(ICar car);
    //是司机就应该会驾驶汽车
    public void drive();
}
class Driver_ implements IDriver2 {
    private ICar car;
    @Override
    public void setCar(ICar car){
        this.car = car;
    }
    //司机的主要职责就是驾驶汽车
    @Override
    public void drive(){
        this.car.run();
    }
}

/*
依赖的三种写法：2、接口声明依赖对象
 */
interface IDriver3 {
    //是司机就应该会驾驶汽车
    public void drive();
}

class Driver3 implements IDriver3 {
    private ICar car;

    //构造函数注入
    public Driver3(ICar car) {
        this.car = car;
    }

    //司机的主要职责就是驾驶汽车
    @Override
    public void drive() {
        this.car.run();
    }
}